package com.pfdu.simplescheduler.strategy;

import com.pfdu.simplescheduler.config.SimpleSchedulerConfig;
import com.pfdu.simplescheduler.node.AppNode;
import com.pfdu.simplescheduler.node.NodeContext;
import com.pfdu.simplescheduler.repo.NodeRepo;
import com.pfdu.simplescheduler.common.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigInteger;
import java.util.List;

/**
 * 任务筛选策略
 * 用任务ID除以应用节点数量，取模，用余数与当前节点的序号比较，
 * 相等，当前节点就锁定该任务并执行，
 * 不相等,就忽略该任务，让其他节点处理。
 */
@Component
public class IdHashFilter implements FilterStrategy {

    @Autowired
    private NodeContext currentNode;

    @Autowired
    SimpleSchedulerConfig config;

    @Autowired
    private NodeRepo nodeRepo;

    @Override
    public boolean accept(Task task) {
        // 当前节点还未注册，就先不拿取任务，直到注册完成才拿取任务并执行。
        if(currentNode==null || currentNode.currentSerialNo()==0)
            return false;

        // 获取节点数量
        int nodeSize = 0;
        List<AppNode> appNodes = nodeRepo.listAvailable(config.getHeartBeatInterval());
        if (appNodes == null || appNodes.size() == 0)
            return false;
        else
            nodeSize = appNodes.size();

        // 任务ID除以节点数量，取模
        BigInteger taskId = task.getId();
        BigInteger remainder = taskId.mod(BigInteger.valueOf(nodeSize));

        // 余数和当前节点序号（有效序号）比较
        int effectiveSerialNo = appNodes.lastIndexOf(currentNode.getCurrentNode()); // 有效序号，即过滤掉已停止心跳的节点后的实际排名(序号)。
        if (remainder.intValue() == effectiveSerialNo)
            return true;
        else
            return false;
    }
}
